package com.soap.desensitize.strategy.json;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.soap.desensitize.encry.IDesensitization;
import com.soap.desensitize.encry.json.AbstractJsonEncry;
import com.soap.desensitize.exception.strategy.DecodeException;
import com.soap.desensitize.exception.strategy.EncodeException;
import com.soap.desensitize.strategy.rreversible.symmetry.DesStrategy;
import com.soap.desensitize.util.JsonUtils;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * @desc java对象转Json对象
 * @author BuffPlum
 * @time 2022-04-29
 */
public  class JsonObjStrategy extends AbstractJsonEncry<Object> {

    public JsonObjStrategy() {
        super(DesStrategy.getInstance());
    }

    private static JsonObjStrategy instance = null;
    /**
     * @desc 获得实例
     * @return
     */
    public static synchronized AbstractJsonEncry getInstance(){
        if(instance == null){
            instance = new JsonObjStrategy();
        }
        return instance;
    }

    /**
     * @desc 传入加密策略 默认还没有设置 最好是可逆的加密
     * @param encry
     * @desc 有参构造器
     */
    public JsonObjStrategy(IDesensitization encry) {
        super(encry);
    }

    /**
     * @desc 将对象转换为为加密后的json对象
     * @param data obj对象
     * @return
     * @throws NoSuchAlgorithmException
     * @throws EncodeException
     * @throws JsonProcessingException
     * @throws InvocationTargetException
     * @throws IllegalAccessException
     */
    @Override
    public String encode(Object data) throws EncodeException {
        Map<String, Object> map = entityEncode(data);
        ObjectMapper mapper=new ObjectMapper();
        String json = null;
        try {
            json = mapper.writeValueAsString(map);
        } catch (JsonProcessingException e) {
            throw new EncodeException("json加密异常");
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return  json;
    }


    /**
     * @desc 将
     * @param data obj对象
     * @return 解密后的数据
     * @throws NoSuchAlgorithmException
     * @throws EncodeException
     */
    @Override
    public Object decode(String data) throws DecodeException {
//        Object map = entityDecode(data);
        Map<?, ?> map = (Map<?, ?>) (JsonMapStrategy.getInstance(this.getEncry()).decode(data));
        return  map;
    }






    /**
     * @desc 判断类型根据类型解密
     * @param value
     * @return
     * @throws NoSuchAlgorithmException
     * @throws EncodeException
     * @throws JsonProcessingException
     * @throws InvocationTargetException
     * @throws IllegalAccessException
     */
    private Object judgeAndDecrypt(Object value){
        Object str=null;
        try {
            switch (value.getClass().getName()){
                case "java.util.LinkedHashMap":
                    str=entityDecode(value);
                    break;
                case "java.lang.String":
                     str = encry.decode(value);
                    break;
            }
        } catch (DecodeException e) {
            throw new RuntimeException(e);
        }
        return str;
    }





    /**
     * @desc 解密并返回json对象
     * @param data
     * @return
     * @throws NoSuchAlgorithmException
     * @throws EncodeException
     * @throws JsonProcessingException
     * @throws InvocationTargetException
     * @throws IllegalAccessException
     */
    private Object entityDecode(Object data) throws DecodeException {
        try {
            Map<String,Object> map =new HashMap<>();
            ObjectMapper mapper=new ObjectMapper();
            Map<String,Object> source=null;
            if(data.getClass().getName().equals("java.util.LinkedHashMap")||data instanceof LinkedHashMap){
                source= (Map<String, Object>) data;
            }else{
                source = mapper.readValue((String) data,new TypeReference<Map<String, Object>>() {});
            }

            for(String key: source.keySet()){
                Object value = source.get(key);
    //            String className = value.getClass().getName();
                Object  str = judgeAndDecrypt(value);
    //            System.out.println("strstrstrstrstrstrstrstrstrstrstrstrstrstrstrstr==="+str);
                map.put(key,str);

            }

            return (Object)mapper.writeValueAsString(map);
        } catch (JsonProcessingException e) {
            throw new DecodeException("解密错误，Json反序列化异常");
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }


    /**
     * @desc 对传入的对象进行加密 并返回map对象
     * @param data 传入的对象
     * @return
     * @throws IllegalAccessException
     * @throws InvocationTargetException
     * @throws NoSuchAlgorithmException
     * @throws EncodeException
     * @throws JsonProcessingException
     */
    private Map<String, Object> entityEncode(Object data) throws EncodeException {
        Map<String, Object> map = null;
        try {
            Class<?> classx = data.getClass();
            Method[] methods = classx.getMethods();
            map = new HashMap<String, Object>();
            for (int i = 0; i < methods.length; i++) {
                Method everymethods = methods[i];
                if (everymethods.getName().indexOf("get") == 0) {
                    if (everymethods.getName().substring(3).equals("Class")) {
                        continue;
                    }
                    Object fieldValue = everymethods.invoke(data);
                    Object str = JsonUtils.judgeAndEncode(fieldValue,encry);
                    map.put(everymethods.getName().substring(3,4).toLowerCase()+everymethods.getName().substring(4),str);
                }
            }
        } catch (IllegalAccessException e) {
            throw new EncodeException("非法访问 IllegalAccessException");
        } catch (InvocationTargetException e) {
            throw new EncodeException("调用目标异常 InvocationTargetException");
        }

        return map;
    }
}
